package com.contexticon.TableEditorsRenderers;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics2D;

import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.geom.Rectangle2D;
import java.math.BigDecimal;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;


import com.contexticon.Listeners.PopupListener;
import com.contexticon.Transcriber2.Transcriber5;
import com.contexticon.logic.TableVerifier;



public class TableCellLongTextEditor extends AbstractCellEditor implements
TableCellEditor, ActionListener, DocumentListener, FocusListener {
	Color currentColor;
	JButton button;
	JColorChooser colorChooser;
	JDialog dialog;
	final JTextArea jtext;
	//TableVerifier verifier;
	protected static final String EDIT = "edit";
	final JTable table;
	
	

	public TableCellLongTextEditor() {
		jtext = new JTextArea();
		jtext.setWrapStyleWord(true);
		jtext.setLineWrap(true);
		//jtext.setBackground(Color.LIGHT_GRAY);
		table = Transcriber5.table;
		jtext.addMouseListener(new PopupListener());
		
		// the text area will have its own focus listener
		jtext.addFocusListener(this);		// set up the keyboard shortcuts

		// add listener to the text area
		// listen to update events
		// eg. when text is edited, update the height of the row
	    final Document document = jtext.getDocument();
	    document.addDocumentListener(this);
		
		Action splitAction = new AbstractAction() {
			
			DefaultTableModel model = (DefaultTableModel) Transcriber5.table.getModel();
			
			public void actionPerformed(ActionEvent e) {

				int rowSelected = table.getSelectedRow();
				int noRows = table.getRowCount();
				int cursorPosition = jtext.getCaretPosition();
				String leftString = jtext.getText().substring(0, cursorPosition);
				String rightString = jtext.getText().substring(cursorPosition,
						jtext.getText().length());

				// if cursor is at the beginning of the utterance (or cell is empty)
				if (leftString.length()==0) {
					// set start time to current playback time
					model.setValueAt(new Float(Transcriber5.playerTest.getCurrentTime()), rowSelected, 0);

					// middle 
				} else if (rightString.length()>0) {

					model.setValueAt(leftString, rowSelected, 2);
					jtext.setText(leftString);
					System.out.println("middle");
					model.insertRow(rowSelected+1, new Object[] {new Float(Transcriber5.playerTest.getCurrentTime()),
							model.getValueAt(rowSelected, 1), rightString });
					model.setValueAt(new Float(Transcriber5.playerTest.getCurrentTime()), rowSelected, 1);
					Transcriber5.table.setRowSelectionInterval(rowSelected+1, rowSelected+1);
					Transcriber5.table.editCellAt(rowSelected+1, 2);
					
					// Set cursor position to the beginning of the new row
					jtext.requestFocus();
					jtext.setCaretPosition(0);
					
					
					// end	
				} else {

					System.out.println("end");
					model.setValueAt(new Float(Transcriber5.playerTest.getCurrentTime()), rowSelected, 1);

					model.insertRow(rowSelected+1, new Object[] {new Float(Transcriber5.playerTest.getCurrentTime()),
							null, null });
					Transcriber5.table.setRowSelectionInterval(rowSelected+1, rowSelected+1);
					Transcriber5.table.editCellAt(rowSelected+1, 2);


				}



			}

		};// end of keyboard shortcut action 'splitAction'




		Action lastUtterance = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {

				// read start and end time from selected row
				int selectedRow = table.getSelectedRow();
				Float startTime = (Float) table.getModel().getValueAt(selectedRow, 0);
				Float endTime = (Float) table.getModel().getValueAt(selectedRow, 1);
				
				// get the start of last utterance
				//Transcriber5.playerTest.setCurrentTime(time);
				
				if ((endTime == null) || (endTime == (float) 0)) {
					// if endTime is empty or 0
					Transcriber5.playerTest.setCurrentTime(startTime);
					Transcriber5.playerTest.play();
				} else {
					// if endTime has proper value
					Transcriber5.playerTest.playMedia(Transcriber5.getaTranscript().getFilepath(), (startTime/1000),
							(endTime/1000));
				}
						

			}
		};

		Action increaseStartTime = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {

				//Increase Start Time by 100ms
				int selectedRow = table.getSelectedRow();
				Float startTime = ((Float) table.getValueAt(selectedRow, 0) + 100);
				Float endTime = (Float) table.getModel().getValueAt(selectedRow, 1);
				table.getModel().setValueAt(startTime, selectedRow, 0);

				//replay current utterance from new beginning
				if ((endTime == null) || (endTime == (float) 0)) {
					// if endTime is empty or 0
					Transcriber5.playerTest.setCurrentTime(startTime);
					Transcriber5.playerTest.play();
				} else {
					// if endTime has proper value
					Transcriber5.playerTest.playMedia(Transcriber5.getaTranscript().getFilepath(), (startTime/1000),
							(endTime/1000));
				}

			}
		};

		Action decreaseStartTime = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {

				//Decrease Start Time by 100ms
				int selectedRow = table.getSelectedRow();
				Float startTime = ((Float) table.getValueAt(selectedRow, 0) - 100);
				Float endTime = (Float) table.getModel().getValueAt(selectedRow, 1);
				table.getModel().setValueAt(startTime, selectedRow, 0);

				//replay current utterance from new beginning
				if ((endTime == null) || (endTime == (float) 0)) {
					// if endTime is empty or 0
					Transcriber5.playerTest.setCurrentTime(startTime);
					Transcriber5.playerTest.play();
				} else {
					// if endTime has proper value
					Transcriber5.playerTest.playMedia(Transcriber5.getaTranscript().getFilepath(), (startTime/1000),
							(endTime/1000));
				}

			}
		};

		Action increaseEndTime = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {

				//Increase End Time by 100ms
				int selectedRow = table.getSelectedRow();
				Float endTime = (Float) table.getValueAt(selectedRow, 1);
				//make sure endTime is not null
				if (endTime == null) {
					endTime = (float) 0;
				};
				table.getModel().setValueAt((endTime + 100), selectedRow, 1);

				//replay last second of current utterance
				Float time = (Float) table.getModel().getValueAt(selectedRow, 1);
				Transcriber5.playerTest.playMedia(Transcriber5.getaTranscript().getFilepath(),
						((endTime + 100 - 1000)/1000),
						((endTime + 100)/1000));
				//Transcriber5.playerTest.setCurrentTime(time);
				//Transcriber5.playerTest.play();

			}
		};

		Action decreaseEndTime = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {

				//Decrease End Time by 100ms
				int selectedRow = table.getSelectedRow();
				Float endTime = (Float) table.getValueAt(selectedRow, 1);
				//make sure endTime is not null
				if (endTime == null) {
					endTime = (float) 0;
				};
				table.getModel().setValueAt((endTime - 100), selectedRow, 1);

				//replay current utterance from beginning
				Float time = (Float) table.getModel().getValueAt(selectedRow, 0);
				Transcriber5.playerTest.playMedia(Transcriber5.getaTranscript().getFilepath(),
						((endTime - 100 - 1000)/1000),
						((endTime - 100)/1000));Transcriber5.playerTest.setCurrentTime(time);
						//Transcriber5.playerTest.play();

			}
		};

		Action nextPeriod = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				
				// get current cursor position
				int caretPos = jtext.getCaretPosition();
				
				// get text to the right of the cursor
				String text = jtext.getText().substring(caretPos,
						jtext.getText().length());
				
				// search for "." and return position
				int periodPos = text.indexOf(".");
				
				// set cursor to that position
				jtext.setCaretPosition(caretPos + periodPos + 1);
				
			}
		};
		
		// splitting
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control ENTER"),"split");
		jtext.getActionMap().put("split", splitAction);
		// replaying utterance
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control L"),"lastShr");
		jtext.getActionMap().put("lastShr", lastUtterance);
		// adjusting start time
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control UP"),"incStartTime");
		jtext.getActionMap().put("incStartTime", increaseStartTime);
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control DOWN"),"decStartTime");
		jtext.getActionMap().put("decStartTime", decreaseStartTime);
		// adjusting end time
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control RIGHT"),"incEndTime");
		jtext.getActionMap().put("incEndTime", increaseEndTime);
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control LEFT"),"decEndTime");
		jtext.getActionMap().put("decEndTime", decreaseEndTime);
		// jump to next period (".")
		jtext.getInputMap().put(KeyStroke.getKeyStroke("control PERIOD"),"nextPeriod");
		jtext.getActionMap().put("nextPeriod", nextPeriod);



		// set up the keyboard shortcuts
		Action pauseAction = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				Transcriber5.playerTest.pause();
			}
		};


		jtext.getInputMap().put(KeyStroke.getKeyStroke("control P"),
				"pauseShr");
		jtext.getActionMap().put("pauseShr", pauseAction);	








	}

	// not sure what this is doing
	public void actionPerformed(ActionEvent e) {

		if (EDIT.equals(e.getActionCommand())) {
			// The user has clicked the cell, so
			// TableCellLongTextEditor. bring up the dialog.

			fireEditingStopped(); // Make the renderer reappear.

		} else { // User pressed dialog's "OK" button.
			// currentColor = colorChooser.getColor();
		}

	}



	@Override
	public Component getTableCellEditorComponent(JTable table, Object value,
			boolean isSelected, int row, int column) {

		jtext.setText((String) value);		


		// figure out how many lines we need
		if (value != null) {

			// set to default
			// set height of the selected row
			table.setRowHeight(table.getRowHeight());			
			//table.setRowHeight(row, (noLines + 1) * table.getRowHeight());
			table.setRowHeight(row, (int) jtext.getPreferredSize().getHeight()+table.getRowHeight());
		}

		return jtext;
	}

	@Override
	public Object getCellEditorValue() {

		System.out.println("Table content:" + Transcriber5.table.getModel().getValueAt(table.getSelectedRow(), 2));
		return jtext.getText();

	}

	
	
	
	// methods listening to the edits in the text area
	public void updateRowHeight() {
		table.setRowHeight(table.getSelectedRow(), (int) jtext.getPreferredSize().getHeight()+table.getRowHeight());
	}
	
	// document events
	public void changedUpdate(DocumentEvent documentEvent) {
		System.out.println("Changed update");
		// added conditional to avoid ArrayIndexOutOfBoundExceptio
		
		/**
		if (table.getSelectedRow()!=-1) {
			table.getModel().setValueAt(jtext.getText(), table.getSelectedRow(), 2);
		}
		**/
		
		SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
            	updateRowHeight();
            }
        });
	}

	public void insertUpdate(DocumentEvent documentEvent) {
		System.out.println("Insert update");
		// added conditional to avoid ArrayIndexOutOfBoundException
		//if (table.getSelectedRow()!=-1) {
		//	table.getModel().setValueAt(jtext.getText(), table.getSelectedRow(), 2);
		//}
		
		// here we need to delay further actions because the row selected has not yet been updated

		SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
            	updateRowHeight();
            }
        });
 
		
		// System.out.println("Model:" + Transcriber5.table.getValueAt(Transcriber5.table.getSelectedRow(), 2));

	}

	public void removeUpdate(DocumentEvent documentEvent) {
		// added conditional to avoid ArrayIndexOutOfBoundException
		
		/**
		System.out.println("Remove update");

		if (table.getSelectedRow()!=-1) {
			table.getModel().setValueAt(jtext.getText(), table.getSelectedRow(), 2);
		}
		**/
		
		
		SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
            	updateRowHeight();
            }
        });		
        
	}
	
	
	
	
	public void focusGained(FocusEvent e) {

		// keeps track of last selected row
		Transcriber5.lastSelectedRow = table.getSelectedRow();
		//System.out.println("Focus gained at row "+ lastSelectedRow);
		
		//System.out.println("Model contents: " + table.getValueAt(lastSelectedRow, 2));
	}

	public void focusLost(FocusEvent e) {
		// TODO Auto-generated method stub
		System.out.println("Focus lost: ");
		
		table.setRowHeight(table.getRowHeight());	
		
		DefaultTableModel ourModel = (DefaultTableModel) table.getModel();
		// check the last row
		int noRows = ourModel.getRowCount();
		Object lastTime = ourModel.getValueAt(noRows-1, 1);
		
		
		// update the model
		//String editText = jtext.getText();
		//ourModel.setValueAt(editText, Transcriber5.lastSelectedRow , 2);
		
		// checks whether the focus was lost from the table
		// or from a text area
		String utteranceContent = null;
		if (e.getOppositeComponent() instanceof JTable) {
		     // get the content from the last selected row
			if (Transcriber5.lastSelectedRow >=0) {
				utteranceContent = (String) ourModel.getValueAt(Transcriber5.lastSelectedRow , 2);
				 System.out.println("lastSelectedRow: " + Transcriber5.lastSelectedRow );
				System.out.println("Model: " + utteranceContent);
			}	
		} else if (e.getOppositeComponent() instanceof JTextArea) {	
			// get the content from the text area
			//jtext = (JTextArea) e.getSource();
			 utteranceContent = jtext.getText();
			 
			System.out.println("Text area: " + utteranceContent); 
			System.out.println("Model: " + ourModel.getValueAt(Transcriber5.lastSelectedRow , 2)); 
		} else {
			System.out.println("None of the above");

			
		}
		
		
		// if the last row is selected
		// and the end time is not set
		// utteranceContent is not empty
		if ((Transcriber5.lastSelectedRow ==(noRows-1)) && (lastTime ==null) && (null!=utteranceContent) && (utteranceContent.length()>0)) {
			long currentTime = Transcriber5.playerTest.getCurrentTime();
			// set the current time to the last row, as end time
			//ourModel.setValueAt(currentTime, lastSelectedRow, 1);
			// add a new utterance
			//ourModel.addRow(new Object[]{new Float(currentTime), null, null});

		}
		
		
	}

}
